﻿using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;

public class PuzzleSystem : MonoBehaviour
{
    public RectTransform BGRect;    // 新增變數，背景圖的RectTransform、盤面中行與列的珠子數、位移的距離
    public int rowCount = 5;
    public int columnCount = 6;
    private Vector2 addPos = new Vector2(120, 120);

    public List<Rune> runes = new List<Rune>(); // 储存版面所有的符石
    public List<List<Rune>> runeGroups = new List<List<Rune>>();    // 二维列表储存符石的群组

    public int removeCount = 3; // 定义多少颗符石消除（可以调整为2消或其他）

    [System.Serializable]
    public struct Combo // 定义 Combo 结构体
    {
        public Rune.RuneType type;  // 符石的属性
        public int count;   // 计算该Combo中消除符石的总数
    }

    public Combo[] runeCombo; // 声明Combo数组

    public bool hasRemoved = false; // 判断是否要重复进行查找群组， combo等

    private void Start()
    {
        InitGrid();
        do
        {
            RuneCreate();
            RuneGroup();
            RuneCombo();
            RuneRemove();
        } while (hasRemoved);
    }

    void InitGrid() // 新增初始化盤面的函式InitGrid，函式當中使用兩層的迴圈，在盤面中每個位置新增珠子
    {
        addPos.x = BGRect.sizeDelta.x / columnCount;
        addPos.y = BGRect.sizeDelta.y / rowCount;
        for (int r = 0; r < rowCount; r++)
        {
            for (int c = 0; c < columnCount; c++)
            {
                GameObject runeObj = Instantiate(Resources.Load("Prefabs/Rune")) as GameObject; // 產生珠子物件
                RectTransform runeRect = runeObj.GetComponent<RectTransform>();
                runeRect.SetParent(BGRect); // 設定珠子物件的父物件
                runeRect.localScale = Vector2.one;  // 设定比例
                runeRect.anchoredPosition = new Vector2(c * addPos.x, r * addPos.y);    // 设定位置

                // Rune data init
                Rune rune = runeObj.GetComponent<Rune>();   // 抓取珠子物件下的Rune腳本，修改Rune腳本下的row和column，接著呼叫RuneCreate函式
                rune.type = Rune.RuneType.Null; // 代入Null属性
                rune.row = r;
                rune.column = c;

                rune.width = BGRect.sizeDelta.x / columnCount;
                rune.height = BGRect.sizeDelta.y / rowCount;

                runes.Add(rune);    // 将生成的符石加入到一维列表中
            }
        }

        for (int index = 0; index < runes.Count; index++)   // 设定Rune脚本的linkRunes，顺序为右上左下的符石
        {
            if (runes[index].column != columnCount - 1) // 判断排除四边与角落的链接，例如最下列的符石不会有下面符石的链接
                runes[index].linkRunes.Add(runes[index + 1]);
            if (runes[index].row != rowCount - 1)
                runes[index].linkRunes.Add(runes[index + columnCount]);
            if (runes[index].column != 0)
                runes[index].linkRunes.Add(runes[index - 1]);
            if (runes[index].row != 0)
                runes[index].linkRunes.Add(runes[index - columnCount]);
        }
    }

    void RuneCreate()  // 在RuneCreate函式中，使用Random隨機一個珠子類型編號，並且將該編號帶入珠子的類型中
    {
        foreach (Rune rune in runes)    // 对runes进行遍历
        {
            rune.group = false; // 初始化 group 布尔值
            rune.removed = false;   // 初始化 removed 布尔值
            if (rune.type == Rune.RuneType.Null)    //  当符石属性为Null时，赋予新属性
            {
                int typeNum = Random.Range(0, (int)Rune.RuneType.Null);
                rune.type = (Rune.RuneType)typeNum;
            }
        }
    }

    void FindRuneMembers(Rune rune, int groupNum)
    {
        foreach (Rune linkRune in rune.linkRunes)   // 遍历与当前符石相连的符石，也就是linkRunes
        {
            if (linkRune.type == rune.type && linkRune.group == false)
            {
                runeGroups[groupNum].Add(linkRune); // 加入当前符石
                linkRune.group = true;  // 设定Group值
                linkRune.groupNum.text = groupNum.ToString();   // 设定显示文字
                FindRuneMembers(linkRune, groupNum);    // 找相邻符石的linkRunes，直到所有相同属性的珠子都加入到群主为止
            }
        }
    }

    void RuneGroup()    // 分群函数
    {
        runeGroups.Clear(); // 因为会重复使用，所以初始化群组
        foreach (Rune rune in runes)    // 遍历查找没有加入群组的符石
        {
            if (rune.group == false)    // 判断该珠子是否已经加入群组
            {
                runeGroups.Add(new List<Rune>());   // 新建符石List，并新增到runeGroups中
                int groupNum = runeGroups.Count - 1;  // 定义群组编号，并将数值设定为新增的List编号
                runeGroups[groupNum].Add(rune); // 将目前这颗没有群组的符石加入到新增的List中
                rune.group = true;  // 表示珠子已经加入到群组中
                rune.groupNum.text = (groupNum).ToString(); // 设定显示文字为群组编号
                FindRuneMembers(rune, groupNum);    // 调用FindRuneMember函数，实参为当前珠子和编号
            }
        }
    }

    void FindRemoveRune(Rune rune, int dir, int length, int comboIndex) // 符石，搜寻方向，搜寻长度，combo编号
    {
        int runeCount = 0;  // 声明计算相连符石的整数
        int runeIndex = runes.IndexOf(rune);    // 声明珠子编号
        for (int index = runeIndex; index <= length; index += dir)  // 从转入的符石开始，到转入的搜寻长度结束，增加数值为搜寻方向
        {
            if (runes[index].type == rune.type) // 当转入的符石属性与当下的珠子属性相同时
            {
                runeCount++;    // runeCount自增
            }
            else
            {
                break;  // 否则跳出循环
            }
        }
        if (runeCount >= removeCount)
        {
            for (int index = runeIndex; index < runeIndex + (runeCount * dir); index += dir)    // 起点与方向相同，只搜寻到runeCount数量为止
            {
                if (runes[index].removed == false)  // 当前符石的removed为false时，将对应combo下的count加1，以计算该combo总数
                    runeCombo[comboIndex].count += 1;
                runes[index].removed = true;    // 将当前符石的removed值设为true，这时该符石会被视为需要消除的符石
                runes[index].removeText.text = "C"; // 修改text
            }
        }
    }

    void RuneCombo()
    {
        runeCombo = new Combo[runeGroups.Count];    // 初始化runeCombo数组，大小与总群组数相同
        foreach (List<Rune> runeGroup in runeGroups)    // 针对符石总群组进行遍历
        {
            int comboIndex = runeGroups.IndexOf(runeGroup); // 声明总数变数comboIndex，将当前群组编号赋值给他
            runeCombo[comboIndex].type = runeGroup[0].type; // 将当前Combo符石属性设定为当前群组属性
            runeCombo[comboIndex].count = 0;    // Combo的珠子数量为0
            foreach (Rune rune in runeGroup)    // 针对当前群组进行遍历
            {
                FindRemoveRune(rune, 1, columnCount * (rune.row + 1) - 1, comboIndex);
                // 往右搜寻，参数为符石，右1，搜寻长度为该列最右边的符石，combo编号为comboIndex
                FindRemoveRune(rune, columnCount, columnCount * (rowCount - 1) + rune.column, comboIndex);
                // 往上搜寻，参数为符石，搜寻方向为上方columnCount，搜寻长度为该行最上面的符石，combo编号为comboIndex
            }
        }
    }

    void RuneRemove()   // 处理符石消除与落下
    {
        foreach (Rune rune in runes)    // 针对每一个符石重设属性
        {
            if (rune.removed == true)
            {
                rune.type = Rune.RuneType.Null; // 需要被移除的符石，属性转为Null
                hasRemoved = true;  // 将hasRemoved设为true，这时Start函数中的循环将会执行
                rune.removeText.text = "";  // 消除标记
            }
            rune.groupNum.text = "";    // 消除数值标记
        }
        foreach (Rune rune in runes)    // 针对每一个符石做掉落判定
        {
            if (rune.type == Rune.RuneType.Null)    // 当找到属性为Null时
            {
                for (int index = runes.IndexOf(rune); index <= columnCount * (rowCount - 1) + rune.column; index += columnCount)
                {   // 往符石的上方搜寻
                    if (runes[index].type != Rune.RuneType.Null)    // 当找到非Null属性的符石时
                    {
                        rune.type = runes[index].type;  // 把当前符石属性设定为该珠子属性
                        runes[index].type = Rune.RuneType.Null; // 该符石设定为Null属性
                        break;  //跳出循环
                    }
                }
            }
        }
    }
}
